﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml;
using System.Reflection;

namespace Clandestine.Conversations
{
    public class Conversation
    {
        public static Dictionary<string, Conversation> Conversations = new Dictionary<string, Conversation>();

        public ConversationPart StartPart;
        public string Name = string.Empty;
        public Dictionary<string, DialogueWindow> DialogueWindows = new Dictionary<string, DialogueWindow>();

        public Conversation(string filename)
            : this(new XmlTextReader(filename)) { }

        public Conversation(XmlTextReader xml)
        {
            // Get name
            while (xml.Read())
                if ((xml.NodeType == XmlNodeType.Element) && (xml.Name == "conversation"))
                {
                    this.Name = xml.GetAttribute("name");
                    break;
                }

            // Start the parsing!
            List<ConversationPart> AwaitingPointer = ParseXML(this, xml, "conversation", out StartPart);
            
            // Add final null pointers
            foreach (ConversationPart cp in AwaitingPointer)
                cp.NextPart = null;
        }

        public static List<ConversationPart> ParseXML(Conversation c, XmlTextReader xml, string endElement, out ConversationPart start)
        {
            // This list contains all ConversationParts that are still awaiting the NextPart pointer to be filled in.
            List<ConversationPart> AwaitingPointer = new List<ConversationPart>();
            bool assignedStart = false; // stupid out params
            start = new TextPart(); // will never get used.

            // Loop through and find <part>s ( & <speaker>s)
            while (!((xml.NodeType == XmlNodeType.EndElement) && (xml.Name == endElement)) && xml.Read())
            {
                // <part>
                if ((xml.NodeType == XmlNodeType.Element) && (xml.Name == "part"))
                {
                    // Get the type, if it throws an exception, you've probably got an incorrect type=""
                    Type t = Assembly.GetExecutingAssembly().GetType("Clandestine.Conversations." + xml.GetAttribute("type") + "Part", true, true);
                    
                    // Create the part
                    ConversationPart p = (ConversationPart)Activator.CreateInstance(t);
                    p.SpeakerName = xml.GetAttribute("speaker");
                    p.Conversation = c;

                    // Add pointers for those still awaiting them
                    foreach (ConversationPart cp in AwaitingPointer)
                        cp.NextPart = p;

                    // Parse the XML for thise part.
                    AwaitingPointer = p.ParseXML(xml);

                    // Make sure we out the start conversation part so that pointers can be set correctly.
                    if (!assignedStart)
                    {
                        start = p;
                        assignedStart = true;
                    }
                }

                // <speaker>
                if ((xml.NodeType == XmlNodeType.Element) && (xml.Name == "speaker"))
                    c.DialogueWindows.Add(xml.GetAttribute("name"), new DialogueWindow(xml.GetAttribute("name"), xml.GetAttribute("face"), new Point(int.Parse(xml.GetAttribute("x")), int.Parse(xml.GetAttribute("y")))));
            }

            if (!assignedStart) 
                throw new Exception("THERE SHOULD ALWAYS BE A <PART> BUT THERE ISN'T. SHIT A BRICK.");
            return AwaitingPointer;
        }

        public void Start()
        {
            ConversationPart curr = StartPart;
            ConversationPart old = null;
            curr.Window.Visible = true;

            WorldMap.Paused = true;

            while (curr != null)
            {
                if (old != null)
                    if (old.Window != curr.Window)
                    {
                        old.Window.Visible = false;
                        curr.Window.Visible = true;
                    }
                curr.Do();

                // Get next
                old = curr;
                curr = curr.NextPart;
            }
            old.Window.Visible = false;

            WorldMap.Paused = false;
        }

        public static void Start(string name)
        {
            if (Conversations.ContainsKey(name))
                Conversations[name].Start();
            else
                Log.e("Tried to start conversation, \"{0}\", but we don't have any conversation in the dictionary.", name);
        }
    }
}
